package utils

import (
	"fmt"
	"log"
	"strconv"

	yamlConfig "github.com/micro/plugins/v5/config/encoder/yaml"
	"github.com/micro/plugins/v5/config/source/consul"
	"github.com/micro/plugins/v5/config/source/etcd"
	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/vo"
	"go-micro.dev/v5/config"
	"go-micro.dev/v5/config/reader"
	"go-micro.dev/v5/config/reader/json"
	"go-micro.dev/v5/config/source"
	"gopkg.in/yaml.v2"
)

/**
 * 初始化配置中心
 *
 * @param string dataId -----------------------------------------------必传
 * @param any ConfigStruct --------------------------------------------必传
 * @author huwl
 */
func InitConfigCenter(dataId string, ConfigStruct any) {
	// 读取配置文件
	cfg, err := GetConfig(ConfigCenter, "yml")
	if err != nil {
		log.Fatalln("读取配置中心 "+ConfigCenter+" 错误：", err.Error())
	}

	switch ConfigCenter {
	case "etcd":
		// 创建 etcd 配置源
		etcdSource := etcd.NewSource(
			etcd.WithAddress(cfg.GetStringSlice(Env+".addrs")...),                     // etcd 集群地址
			etcd.Auth(cfg.GetString(Env+".username"), cfg.GetString(Env+".password")), // 认证
			etcd.WithPrefix(cfg.GetString(Env+".prefix")+"/"+dataId),                  // 配置路径前缀
			etcd.StripPrefix(true), // 读取时移除前缀
		)

		// 初始化配置管理器
		conf, err := config.NewConfig(config.WithSource(etcdSource))
		if err != nil {
			log.Fatalf("配置初始化失败: %v", err)
		}

		// 加载 etcd 配置
		if err := conf.Load(); err != nil {
			log.Fatalf("配置加载失败: %v", err)
		}

		// 读取配置数据
		if err := conf.Scan(ConfigStruct); err != nil {
			log.Fatalf("读取etcd配置中心数据错误：", err)
		}

		// 动态监控
		watcher, err := conf.Watch()
		if err != nil {
			log.Fatal(err)
		}
		go func(configStruct any) {
			for {
				// 等待变更
				v, err := watcher.Next()
				if err != nil {
					log.Printf("watch error: %s", err)
					continue
				}
				if err := v.Scan(&configStruct); err != nil {
					log.Printf("decode error: %s", err)
				} else {
					log.Println("更新配置：", configStruct)
					// 在这里更新配置，比如重新初始化数据库连接等
					switch dataId {
					case MySqlConfigCenter:
						// 重新初始化 mysql 连接
					}
				}
			}
		}(ConfigStruct)

	case "nacos":
		// 连接配置
		clientConfig := constant.ClientConfig{
			NamespaceId: cfg.GetString(Env + ".name_space_id"),
			Username:    cfg.GetString(Env + ".username"),
			Password:    cfg.GetString(Env + ".password"),
			// TimeoutMs:           cfg.GetUint64(Env + ".timeout_ms"),
			// NotLoadCacheAtStart: cfg.GetBool(Env + ".not_load_cache_at_start"),
			// LogDir:              cfg.GetString(Env + ".not_load_cache_at_start"),
			// CacheDir:            cfg.GetString(Env + ".cache_dir"),
			// LogLevel: cfg.GetString(Env + ".log_level"),
		}

		// 服务中心的配置
		serverConfigs := []constant.ServerConfig{}
		addrs := StringSplit(cfg.GetString(Env+".addrs"), ",")
		for _, addr := range addrs {
			ipAddr := StringSplit(addr, ":")[0]
			port, _ := strconv.ParseUint(StringSplit(addr, ":")[1], 10, 64)
			serverConfigs = append(serverConfigs, constant.ServerConfig{
				IpAddr:      ipAddr,
				ContextPath: cfg.GetString(Env + ".context_path"),
				Port:        port,
				Scheme:      "http",
			})
		}

		// 创建配置中心连接
		configClient, err := clients.NewConfigClient(
			vo.NacosClientParam{
				ClientConfig:  &clientConfig,
				ServerConfigs: serverConfigs,
			},
		)
		if err != nil {
			log.Fatalf("创建配置中心连接错误：", err)
		}

		// 获取配置中心数据
		content, err := configClient.GetConfig(vo.ConfigParam{
			DataId: dataId,
			Group:  "DEFAULT_GROUP",
		})
		if err != nil {
			log.Fatalf("获取配置中心数据错误：", err)
		}

		// yaml解析配置文件
		err = mapTo(content, ConfigStruct)
		if err != nil {
			log.Fatalf(dataId+" yaml解析配置文件出错：", err)
		}

		// 动态监听
		err = configClient.ListenConfig(vo.ConfigParam{
			DataId: dataId,
			Group:  "DEFAULT_GROUP",
			OnChange: func(namespace, group, dataId, data string) {
				fmt.Println("更新配置：", data)
				err = mapTo(data, ConfigStruct)
				if err != nil {
					log.Println("监听配置出错：", err)
				} else {
					// 在这里更新配置，比如重新初始化数据库连接等
					switch dataId {
					case MySqlConfigCenter:
						// 重新初始化 mysql 连接
					}
				}
			},
		})
		if err != nil {
			log.Println("动态监听配置文件出错：", err)
		}

	case "consul":
		consulSource := consul.NewSource(
			consul.WithAddress(cfg.GetString(Env+".addrs")),
			// optionally specify prefix; defaults to:
			// /micro/config/dev
			// /micro/config/test
			// /micro/config/prod
			consul.WithPrefix(cfg.GetString(Env+".prefix")),
			// optionally strip the provided prefix from the keys, defaults to false
			consul.StripPrefix(true),
			source.WithEncoder(yamlConfig.NewEncoder()),
			consul.WithToken(cfg.GetString(Env+".secret_id")),
		)

		// 创建配置
		conf, err := config.NewConfig(
			config.WithReader(json.NewReader(reader.WithEncoder(yamlConfig.NewEncoder()))),
		)
		if err != nil {
			log.Fatalf("配置初始化失败: %v", err)
		}

		// 加载 etcd 配置
		if err := conf.Load(consulSource); err != nil {
			log.Fatalf("配置加载失败: %v", err)
		}

		// 读取配置数据
		if err := conf.Get(dataId).Scan(ConfigStruct); err != nil {
			log.Fatalf("读取consul配置中心数据错误：", err)
		}

		// 动态监控
		watcher, err := conf.Watch(dataId) // 监听路径（如 "database"）
		if err != nil {
			log.Fatal("动态监控错误：", err)
		}

		go func(configStruct any, watcher config.Watcher) {
			for {
				v, err := watcher.Next() // 阻塞直到配置变更
				if err != nil {
					log.Println("Watch error:", err)
					continue
				}

				if err := v.Scan(&configStruct); err != nil { // 解析新配置到结构体
					log.Printf("解析更新配置错误: %s", err)
				} else {
					log.Println("更新配置：", configStruct)
					// 在这里更新配置，比如重新初始化数据库连接等
					switch dataId {
					case MySqlConfigCenter:
						// 重新初始化 mysql 连接
					}
				}
			}
		}(ConfigStruct, watcher)
	}
}

func mapTo(content string, ConfigStruct any) error {
	return yaml.Unmarshal([]byte(content), ConfigStruct)
}
